home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / mips / mips.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  21.3 KB  |  720 lines

  1. (* mips.sml
  2.  *
  3.  * Copyright (c) 1992 by AT&T Bell Laboratories
  4.  *)
  5.  
  6. functor MipsCM(structure C: CODER and E: ENDIAN
  7.              sharing type C.instruction = MipsInstrSet.instruction
  8.              and type C.sdi = MipsInstrSet.sdi) : CMACHINE =
  9. struct
  10.  
  11.   structure M = MipsInstrSet
  12.   open M
  13.   type EA = C.label M.EA
  14.  
  15.   val error = ErrorMsg.impossible
  16.  
  17.   exception BadReal     = C.BadReal
  18.   val align         = fn () => ()
  19.   val mark         = C.mark
  20.   val emitlong         = C.emitLong
  21.   val realconst     = C.emitReal
  22.   val emitstring     = C.emitString
  23.   val newlabel         = M.ImmedLab o C.newLabel
  24.   val immed           = M.Immed 
  25.   val emitSDI        = C.emitSDI
  26.   val emit        = C.emit
  27.  
  28.   fun emitlab(k,ImmedLab lab) = C.emitLabel(lab,k)
  29.     | emitlab _ = error "MipsCM.emitlab"
  30.  
  31.   fun define(ImmedLab lab) = C.define lab
  32.     | define _ = error "MipsCM.define"
  33.  
  34.  
  35.   (* Register Map
  36.      Reg   gc   desc
  37.      -------------------------------------
  38.      0       n    zero
  39.      1     n    temporary reg
  40.      2       y    standard arg
  41.      3       y    standard continuation
  42.      4       y    standard closure
  43.      5       y    standard link
  44.      6-18  y    misc regs
  45.      19    n    limit reg
  46.      20    n    var pointer
  47.      21    n    temporary reg & heapExhausted reg.
  48.      22    n    store pointer
  49.      23    n    allocation pointer
  50.      24       n    base reg
  51.      25    n    temporary reg & maskReg
  52.      26-27 n    reserved for OS kernel
  53.      28       n    C global pointer
  54.      29       n    C stack pointer
  55.      31       n    temporary reg & gclink register
  56.   *)
  57.   val varptr_indexable            = true
  58.   val standardlink                 = Direct(Reg 5)
  59.   val standardarg           = Direct(Reg 2)
  60.   val standardcont           = Direct(Reg 3)
  61.   val standardclosure           = Direct(Reg 4)
  62.   val miscregs                = map (Direct o Reg) 
  63.                                [6,7,8,9,10,11,12,13,14,15,16,17,18]
  64.  
  65.   val limit as Direct limit'          = Direct(M.limitReg)
  66.   val varptr                = Direct(Reg 20)
  67.   val stackptr'                     =      (Reg 29)
  68.  
  69.   val storeptr as Direct storeptr' = Direct(Reg 22)
  70.   val dataptr as Direct dataptr'   = Direct(M.allocReg)
  71.  
  72.   val exnptr                 = Direct(M.exnptrReg)
  73.  
  74.   val floatregs: EA list       = map (Direct o Freg)
  75.                            [0,2,4,6,8,10,12,14,16,18,30]
  76.   val savedfpregs: EA list       = map (Direct o Freg) [20,22,24,26,28]
  77.  
  78.   val arithtemps: EA list       = []
  79.  
  80.   local
  81.       exception NoTmpRegs
  82.       val tmpRegs    = [M.heapExhaustedReg,M.maskReg,M.linkReg,Reg 1]
  83.       val queue         = ref tmpRegs
  84.   in  
  85.       fun getTmpReg()    = case !queue
  86.                        of hd :: rest => (queue := rest; hd)
  87.                 | _ => raise NoTmpRegs
  88.       fun freeTmpReg reg = queue := !queue @ [reg]
  89.   end
  90.  
  91.  
  92.   fun emitBRANCH(cond,rs,rt,lab) = 
  93.       let val flabel = C.newLabel()
  94.       val tmpR = getTmpReg()
  95.       in 
  96.       emitSDI(M.BRANCH(cond,rs,rt,lab,tmpR,flabel));
  97.       C.define flabel;
  98.       freeTmpReg tmpR
  99.       end
  100.  
  101.   fun emitBRANCH_COP1(cond,lab) = 
  102.       let val flabel = C.newLabel()
  103.       val tmpR = getTmpReg()
  104.       in
  105.       emitSDI(M.BRANCH_COP1(cond,lab,tmpR,flabel));
  106.       C.define flabel;
  107.       freeTmpReg tmpR
  108.       end
  109.  
  110.  
  111.   datatype immedSize = IMMED16 | IMMED32
  112.  
  113.   fun immed_size n = if (~32764<=n) andalso (n<=32764) 
  114.              then IMMED16 
  115.              else IMMED32
  116.   fun load_immed(n,r) =  
  117.       case (immed_size n)
  118.     of IMMED16 => emit(M.ADD(r,Reg 0,Immed16Op n))
  119.      | IMMED32 => let val (hi,lo) = M.split n
  120.               in  emit (M.LUI(r,Immed16Off hi));
  121.               emit (M.ADD(r,r,Immed16Op lo))
  122.               end
  123.  
  124.   fun do_immed_arith(instr,rt,rs,n) =
  125.       case (immed_size n)
  126.     of IMMED16 => emit(instr(rt,rs,Immed16Op n))
  127.      | IMMED32 => let 
  128.               val (hi,lo) = M.split n
  129.               val tmpR = getTmpReg()
  130.               in 
  131.               emit (M.LUI(tmpR,Immed16Off hi));
  132.               emit (M.ADD(tmpR,tmpR,Immed16Op lo));
  133.               emit (instr(rt,rs,RegOp tmpR));
  134.               freeTmpReg tmpR
  135.               end
  136.  
  137.   fun do_immed_mem(instr,rt,base,n) =
  138.       case (immed_size n)
  139.     of IMMED16 => emit(instr(rt,base,Immed16Off n))
  140.      | IMMED32 => let 
  141.               val (hi,lo) = M.split n
  142.               val tmpR = getTmpReg()
  143.               in 
  144.               emit (M.LUI(tmpR,Immed16Off hi));
  145.               emit (M.ADD(tmpR,tmpR,RegOp base));
  146.               emit (instr(rt,tmpR,Immed16Off lo));
  147.               freeTmpReg tmpR
  148.               end
  149.  
  150.  
  151.  (*
  152.   * move(a,b) means b <- a
  153.   *)
  154.   val Reg0 = Reg 0
  155.   val RegOp0 = RegOp(Reg 0)
  156.  
  157.   fun move(Direct a, Direct b) =
  158.         (case (reg_rep a, reg_rep b)
  159.           of (Freg' _, Freg' _) => emit(M.MOV_DOUBLE(b,a))
  160.         | (Freg' _, _) => error "MipsCM.move: destination not a float reg"
  161.        | (_, Freg' _) => error "MipsCM.move: source not a float reg"
  162.        | (Reg' a', Reg' b') => if a'=b' then ()
  163.                            else emit(M.ADD(b,a,RegOp0)))
  164.     | move(ImmedLab lab, Direct dst) = emitSDI(LOADADDR(dst,lab,0))
  165.     | move(Immed n, Direct dst) = load_immed(n,dst)
  166.     | move _ = error "MipsCM.move"
  167.  
  168.   fun jmp (Direct r)     = emit(M.JUMP r)
  169.     | jmp (ImmedLab lab) = emitBRANCH(true,Reg0,Reg0,lab)
  170.     | jmp _              = error "MipsCM.jmp: bad target"
  171.  
  172.  
  173.  (*
  174.   * Note:mipsdepend will ensure that nothing generated here
  175.   *     gets reordered.
  176.   *)
  177.   fun testLimit() = emit(M.SLT(M.heapExhaustedReg,dataptr',RegOp(limit')))
  178.  
  179.   val startgc_offset = 4
  180.  
  181.   fun checkLimit(max_allocation, lab, mask) =
  182.       (* NOTE: THIS CODE USES TEMP REGS BY ALIASES.
  183.        Thus it is important that none of the emitted pseudo-instructions
  184.        below uses getTmpReg(), directly or indirectly. *)
  185.     let val lab' = C.newLabel()
  186.      in if max_allocation > 4096
  187.         then (do_immed_arith(M.ADD,M.heapExhaustedReg,dataptr',
  188.                  max_allocation - 4096);
  189.               emit(M.SLT(M.heapExhaustedReg,M.heapExhaustedReg,RegOp(limit'))))
  190.         else ();
  191.         emitBRANCH(false,M.heapExhaustedReg, Reg0, lab');
  192.     do_immed_mem(M.LW,M.heapExhaustedReg,stackptr',startgc_offset);
  193.     move(mask, Direct M.maskReg);
  194.     move(lab, Direct M.linkReg);
  195.         emit(M.JUMP M.heapExhaustedReg);
  196.         C.define lab'
  197.     end
  198.  
  199.   fun beginStdFn(ImmedLab lab, Direct reg) = emitSDI(M.SETBASEADDR(lab,reg))
  200.  
  201.  (*
  202.   * jmpindexb(x,y) means pc <- (x+y) 
  203.   *)
  204.   fun jmpindexb(ImmedLab lab,Direct y) = 
  205.       let val tmpR = getTmpReg()
  206.       in 
  207.     emitSDI(LOADADDR(tmpR,lab,0));
  208.     emit(M.ADD(tmpR,y,RegOp tmpR));
  209.     emit(M.JUMP tmpR);
  210.     freeTmpReg tmpR
  211.       end
  212.     | jmpindexb _ = error "MipsCM.jmpindexb"
  213.  
  214.  
  215.  (* should be rewritten to use all the temp registers *)
  216.   fun record(vl, Direct z) = let
  217.         open CPS
  218.     val len = List.length vl
  219.     fun f(_,i,nil) = ()
  220.       | f((t1,t2),i,(Direct r, SELp(j,p))::rest) = 
  221.            (* follow ptrs to get the item  *)
  222.         (emit(M.LW(t1,r,Immed16Off(j*4))); f((t2,t1),i,(Direct t1,p)::rest))
  223.       | f(t,i,(Direct r,OFFp 0)::rest) = 
  224.            (*  simple store, last first  *) 
  225.         (emit(M.SW(r,dataptr',Immed16Off(i*4)));  f(t,i-1,rest))
  226.       | f((t1,t2),i,(Direct r, OFFp j)::rest) = 
  227.         (emit(M.ADD(t1,r,Immed16Op(4*j))); 
  228.          f((t2,t1),i,(Direct t1,OFFp 0)::rest))
  229.       | f((t1,t2),i,(ea,p)::rest) =
  230.            (* convert to register-based  *)
  231.         (move(ea,Direct t1);  f((t2,t1),i,(Direct t1,p)::rest))
  232.     val tmpR1 = getTmpReg()
  233.     val tmpR2 = getTmpReg()
  234.       in 
  235.        (* store first word in 0(dataptr') *)
  236.     f((tmpR1,tmpR2),len-1,rev vl); 
  237.     freeTmpReg tmpR1;
  238.     freeTmpReg tmpR2;
  239.     emit (M.ADD(z,dataptr',Immed16Op 4));
  240.     do_immed_arith(M.ADD,dataptr',dataptr',4*len)
  241.       end
  242.     | record _ = error "MipsCM.record: result not a register"
  243.  
  244.   (* recordStore(x, y, alwaysBoxed) records a store operation into mem[x+2*(z-1)].
  245.    * The flag alwaysBoxed is true if the value stored is guaranteed to be boxed.
  246.    *)
  247.     fun recordStore (x, y, _) = record ([
  248.         (Immed(System.Tags.make_desc(3, System.Tags.tag_record)), CPS.OFFp 0),
  249.         (x, CPS.OFFp 0), (y, CPS.OFFp 0), (storeptr, CPS.OFFp 0)
  250.       ], storeptr)
  251.  
  252.  
  253.   fun select(i,Direct v',Direct w) = do_immed_mem(M.LW,w,v',i*4)
  254.     | select(i,ImmedLab lab,Direct w) = emitSDI(LOAD(w,lab,i*4))
  255.     | select _ = error "MipsCM.select: bad dst"
  256.  
  257.  
  258.   fun offset(i,v,Direct w) =
  259.       (case v
  260.      of Direct v'    => do_immed_arith(M.ADD,w,v',i*4)
  261.       | ImmedLab lab => let val tmpR = getTmpReg()
  262.                 in
  263.                 emitSDI(LOADADDR(tmpR,lab,0));
  264.                 do_immed_arith(M.ADD,w,tmpR,i*4);
  265.                 freeTmpReg tmpR
  266.                 end
  267.       | _            => error "MipsCM.offset: bad src")
  268.     | offset _ = error "MipsCM.offset: bad dst"
  269.  
  270.  
  271.  (* fetchindexb(x,y,z) fetches a byte: y <- mem[x+z], 
  272.   *    where y is not x or z 
  273.   *)
  274.   fun fetchindexb(Direct x,Direct y,Immed indx)  = do_immed_mem(M.LBU,y,x,indx)
  275.     | fetchindexb(Direct x,Direct y,Direct indx) = let
  276.           val tmpR = getTmpReg()
  277.       in 
  278.       emit (M.ADD(tmpR,indx,RegOp x));
  279.       emit (M.LBU(y,tmpR,Immed16Off 0));
  280.       freeTmpReg tmpR
  281.       end
  282.     | fetchindexb _ = error "MipsCM.fetchindexb"
  283.  
  284.  
  285.  (* 
  286.   * storeindexb(x,y,z) stores a byte: mem[y+z] <- x. 
  287.   *)
  288.   fun storeindexb(Immed xi,y,z) = 
  289.       let val tmpR = getTmpReg()
  290.       in
  291.       do_immed_arith(M.ADD,tmpR,Reg0,xi);  
  292.       storeindexb(Direct tmpR,y,z);
  293.       freeTmpReg tmpR
  294.       end
  295.     | storeindexb(Direct x,Direct y,Direct indx) =
  296.       let val tmpR = getTmpReg()
  297.       in 
  298.       emit (M.ADD(tmpR,y,RegOp indx));
  299.       emit (M.SB(x,tmpR,Immed16Off 0));
  300.       freeTmpReg tmpR
  301.       end
  302.     | storeindexb(Direct x,Direct y,Immed indx) = do_immed_mem(M.SB,x,y,indx)
  303.     | storeindexb _ = error "MipsCM.storeindexb" 
  304.  
  305.  
  306.  (* 
  307.   * fetchindexl(x,y,z) fetches a word:   y <- mem[x+2*(z-1)] 
  308.   *)
  309.   fun fetchindexl(x,Direct y,Direct z') = 
  310.       let val tmpR = getTmpReg()
  311.       in
  312.       emit(M.SLL(tmpR,z',Int5 1));
  313.       (case x 
  314.            of Direct x' => (emit (M.ADD(tmpR,x',RegOp tmpR));
  315.                 emit (M.LW(y,tmpR,Immed16Off ~2)))
  316.          | Immed n      => do_immed_mem(M.LW,y,tmpR,n-2)
  317.          | ImmedLab lab => 
  318.            let val tmpR2 = getTmpReg()
  319.            in
  320.                emitSDI(M.LOADADDR(tmpR2,lab,0));
  321.                emit(M.ADD(tmpR,tmpR,RegOp tmpR2));
  322.                freeTmpReg tmpR2;
  323.                emit(M.LW(y,tmpR,Immed16Off ~2))
  324.            end);
  325.            freeTmpReg tmpR
  326.       end
  327.     | fetchindexl(x,Direct y,Immed z') =  
  328.       (case x
  329.      of Direct x'    => do_immed_mem(M.LW,y,x',2*(z'-1))
  330.       | Immed n      => do_immed_mem(M.LW,y,Reg0,n+2*(z'-1))
  331.       | ImmedLab lab => emitSDI(LOAD(y,lab,2*(z'-1))))
  332.     | fetchindexl _ = error "MipsCM.fetchindexl"
  333.  
  334.  
  335.  (* 
  336.   * storeindexl(x,y,z) stores a word:    mem[y+2*(z-1)] <- x 
  337.   *)
  338.   fun storeindexl(Direct x,Direct y,Direct z) = 
  339.       let val tmpR = getTmpReg()
  340.       in 
  341.       emit (M.SLL(tmpR,z,Int5 1));
  342.       emit (M.ADD(tmpR,tmpR,RegOp y));
  343.       emit (M.SW(x,tmpR,Immed16Off ~2));
  344.       freeTmpReg tmpR
  345.       end
  346.     | storeindexl(Direct x,Direct y,Immed zi) = do_immed_mem(M.SW,x,y,2*(zi-1))
  347.     | storeindexl(Immed xi,y,z) =  let val tmpR = getTmpReg()
  348.                    in
  349.                        load_immed(xi,tmpR); 
  350.                        storeindexl(Direct tmpR,y,z);
  351.                        freeTmpReg tmpR
  352.                    end
  353.     | storeindexl(ImmedLab lab,y,z) = let val tmpR = getTmpReg()
  354.                       in
  355.                       emitSDI(M.LOADADDR(tmpR,lab,0));
  356.                       storeindexl(Direct tmpR,y,z);
  357.                       freeTmpReg tmpR
  358.                       end
  359.     | storeindexl(Direct x,ImmedLab lab,Immed zi) = 
  360.       let val tmpR = getTmpReg()
  361.       in 
  362.       emitSDI(M.LOADADDR(tmpR,lab,0));  
  363.       do_immed_mem(M.SW,x,tmpR,2*(zi-1));
  364.       freeTmpReg tmpR
  365.       end
  366.     | storeindexl _ = error "MipsCM.storeindexl: bad args"
  367.  
  368.  
  369.  (*
  370.   * three - can *only* be used for commutative operators
  371.   *)
  372.   fun three f (Direct x',Direct y', ea) = 
  373.       (case ea
  374.      of Immed zi     => do_immed_arith(f,x',y',zi)
  375.       | Direct z'    => emit(f(x',y',RegOp z'))
  376.       | ImmedLab lab => let val tmpR = getTmpReg()
  377.                 in
  378.                 emitSDI(M.LOADADDR(tmpR,lab,0));  
  379.                 emit(f(x',y',RegOp tmpR));
  380.                 freeTmpReg tmpR
  381.                 end)
  382.     | three f (Direct x', ea, Direct z') = three f (Direct x',Direct z',ea)
  383.     | three _ _ = error "MipsCM.three: bad args"
  384.  
  385.   fun add(x,y,z)     = three M.ADD (z,x,y)
  386.   fun orb(x,y,z)     = three M.OR  (z,x,y) 
  387.   fun andb(x,y,z)    = three M.AND (z,x,y)
  388.   fun xorb(x,y,z)    = three M.XOR (z,x,y)
  389.  
  390.  (* Subtraction may appear a bit odd. 
  391.   * The MIPS machine instruction and  MIPSCODER.sub both subtract 
  392.   * their second operand from their first operand.
  393.   * The CMACHINE.sub subtracts the first operand from the second.
  394.   * This will certainly lead to endless confusion.
  395.   *
  396.   * sub(a,b,c) mean c <- b-a
  397.   *)
  398.   fun op sub(Immed xi,y,z)           = add(y,Immed (~xi),z)
  399.     | op sub(Direct x,Direct y,Direct z)= emit(M.SUB(z,y,x))
  400.     | op sub(x,Immed 0,dest)            = op sub(x, Direct(Reg0), dest)
  401.     | op sub(x,Immed k,dest)            = let val tmpR = getTmpReg()
  402.                       in
  403.                           do_immed_arith(M.ADD,tmpR,Reg0,k);
  404.                           op sub(x,Direct tmpR,dest);
  405.                           freeTmpReg tmpR
  406.                       end
  407.     | op sub _ = error "MipsCM.sub: mismatched args"
  408.  
  409.  
  410.   fun notb(a,b)     = op sub(a, Immed ~1, b)
  411.  
  412.  
  413.  (* 
  414.   * integer arithmetic with overflow trapping - addt subt mult divt
  415.   *)
  416.   fun addt (Immed ai,Immed bi,Direct rd) =
  417.       (load_immed(ai,rd);  do_immed_arith(M.ADD,rd,rd,bi))
  418.     | addt args = add args
  419.  
  420.   val subt = op sub
  421.  
  422.  
  423.  (* The Mips multiplies two 32-bit quantities to get a 64-bit result.
  424.   * That result fits in 32 bits if and only if the high-order word is zero
  425.   * or negative one, and it has the same sign as the low order word.
  426.   * Thus, we can add the sign bit of the low order word to the high order 
  427.   * word, and we have overflow if and only if the result is nonzero.
  428.   *)
  429.   fun mult(ea,y as Direct y') =
  430.       let val tmpR = getTmpReg()
  431.       in 
  432.       (case ea
  433.        of Immed xi  => 
  434.            (do_immed_arith(M.ADD,tmpR,Reg0, xi);  mult(Direct tmpR,y))
  435.         | Direct x' => 
  436.            let val ok = C.newLabel()
  437.            in  emit (M.MULT(x',y'));
  438.            emit (M.MFLO y');
  439.            emit (M.SLT(y',y',RegOp (Reg0)));
  440.            emit (M.MFHI tmpR);
  441.            emit (M.ADD(tmpR,y',RegOp tmpR));
  442.            emit (M.MFLO y');
  443.            emitBRANCH(true,tmpR,Reg0,ok);
  444.            emit (M.LUI(tmpR,Immed16Off 32767));
  445.            emit (M.ADD(tmpR,tmpR,RegOp tmpR));
  446.            C.define ok
  447.            end
  448.         | _ => error "MipsCM.mult");
  449.       freeTmpReg tmpR
  450.       end
  451.     | mult _ = error "MipsCM.mult: result not a register"
  452.  
  453.  
  454.  (*
  455.   * divt(a,b) means b <- b div a 
  456.   *)
  457.   fun divt(Direct x',Direct y') = 
  458.       let val oklabel = C.newLabel()
  459.       in 
  460.       (* emit (M.DIV(y',x')); *)
  461.       emitBRANCH(false,Reg0,x',oklabel);
  462.       emit(M.BREAK 7);
  463.       C.define oklabel;
  464.       emit (M.DIV(y',x'));
  465.       emit (M.MFLO y')
  466.       end
  467.     | divt(Immed xi, y) = 
  468.       let val tmpR = getTmpReg()
  469.       in
  470.       do_immed_arith(M.ADD,tmpR,Reg0,xi);
  471.       divt(Direct tmpR,y);
  472.       freeTmpReg tmpR
  473.       end
  474.     | divt _ = error "MipsCM.divt: mismatched args"
  475.  
  476.  
  477.   fun ashr(shamt,Direct rt,Direct rd) =
  478.       (case shamt
  479.        of Direct rs => emit(M.SRAV(rd,rt,rs))
  480.         | Immed n      => 
  481.            if n >= 32 orelse n < 0 then
  482.            error "MipsCM.ashr: Too large a shift distance"
  483.            else
  484.            emit(M.SRA(rd,rt,Int5 n))
  485.         | _ => error "MipsCM.ashr")
  486.     | ashr(shamt,Immed n,dst) = let val tmpR = getTmpReg()
  487.                 in  
  488.                     load_immed(n,tmpR);
  489.                     ashr(shamt,Direct tmpR,dst);
  490.                     freeTmpReg tmpR
  491.                 end
  492.     | ashr _ = error "MipsCM.ashr: bad args"
  493.  
  494.  
  495.   fun ashl(shamt,Direct rt,Direct rd) =
  496.       (case shamt
  497.        of Direct rs => emit(M.SLLV(rd,rt,rs))
  498.      | Immed n      => 
  499.            if n >= 32 orelse n < 0 then
  500.            error "MipsCM.ashl: Too large a shift distance"
  501.            else
  502.            emit(M.SLL(rd,rt,Int5 n))
  503.      | _ => error "MipsCM.ashl")
  504.     | ashl(shamt,Immed n,dst) = let val tmpR = getTmpReg()
  505.                 in  
  506.                     load_immed(n,tmpR);
  507.                     ashl(shamt,Direct tmpR,dst);
  508.                     freeTmpReg tmpR
  509.                 end
  510.     | ashl _ = error "MipsCM.ashl: bad args"
  511.  
  512.  
  513.  
  514.   datatype condition = NEQ | EQL | LEQ | GEQ | LSS | GTR
  515.  
  516.   fun ibranch(cond,Immed a,Immed b,ImmedLab lab) =
  517.       if  (case cond of EQL => a=b  | NEQ => a<>b | LSS => a<b |
  518.             LEQ => a<=b | GTR => a>b  | GEQ => a>=b)  
  519.       then  emitBRANCH(true,Reg0,Reg0,lab)
  520.       else  ()
  521.     | ibranch(cond,Immed n,Direct t,label) =
  522.       let val tmpR = getTmpReg()
  523.       in  
  524.       load_immed(n,tmpR);
  525.       ibranch(cond,Direct tmpR,Direct t,label);
  526.       freeTmpReg tmpR
  527.       end
  528.     | ibranch(cond,Direct rs,Immed n,label) =
  529.      (*
  530.       * could do a better job of this case (ref.G.Kane, table C.2)
  531.       *)
  532.       let val tmpR = getTmpReg()
  533.       in 
  534.       load_immed(n,tmpR); 
  535.       ibranch(cond,Direct rs,Direct tmpR,label);
  536.       freeTmpReg tmpR
  537.       end
  538.     | ibranch(cond,Direct rs,Direct rt,ImmedLab lab) = 
  539.       (case cond
  540.        of NEQ => emitBRANCH(false,rs,rt,lab)
  541.     | EQL => emitBRANCH(true,rs,rt,lab)
  542.     | cond => let val tmpR = getTmpReg()
  543.           in (case cond
  544.               of LEQ => 
  545.                  (emit(M.SLT(tmpR,rt,RegOp rs)); 
  546.                   emitBRANCH(true,tmpR,Reg0,lab))
  547.                | GEQ => 
  548.                  (emit(M.SLT(tmpR,rs,RegOp rt));
  549.                   emitBRANCH(true,tmpR,Reg0,lab))
  550.                | LSS => 
  551.                  (emit(M.SLT(tmpR,rs,RegOp rt));
  552.                   emitBRANCH(false,tmpR,Reg0,lab))
  553.                | GTR => 
  554.                  (emit(M.SLT(tmpR,rt,RegOp rs));
  555.                   emitBRANCH(false,tmpR,Reg0,lab))
  556.                | _ => error "");
  557.               freeTmpReg tmpR
  558.           end)
  559.     | ibranch _ = error "MipsCM.ibranch: bad args"
  560.  
  561.  
  562.  (*
  563.   * bbs - branch on bit set.
  564.   *)
  565.   fun bbs(Immed k, Direct y, ImmedLab label) =
  566.       let val tmpR = getTmpReg()
  567.       in
  568.       do_immed_arith(M.AND,tmpR,y,Bits.lshift(1,k));
  569.       emitBRANCH(false,tmpR,Reg0,label);
  570.       freeTmpReg tmpR
  571.       end
  572.     | bbs _ = error "MipsCM.bbs: bad args"
  573.  
  574.  
  575.  (* 
  576.   * rangeChk (a, b, lab):  pc <- lab if ((a < 0) or (b <= a)) 
  577.   *)
  578.   fun rangeChk(Immed a, Immed b, ImmedLab lab) =
  579.       if a<0 orelse a>=b then emitBRANCH(true,Reg0,Reg0,lab) else ()
  580.     | rangeChk(Immed a, b, ImmedLab lab) =
  581.       if a<0 then emitBRANCH(true,Reg0, Reg0, lab)  
  582.       else ibranch(GEQ,Immed a,b, ImmedLab lab)
  583.     | rangeChk(Direct a, Direct b', ImmedLab lab) = let
  584.       val tmpR = getTmpReg()
  585.       in
  586.       emit(M.SLTU(tmpR,a,RegOp b')); 
  587.       emitBRANCH(true,Reg0,tmpR,lab);
  588.       freeTmpReg tmpR
  589.       end
  590.     | rangeChk(Direct a, Immed n, ImmedLab lab) = let
  591.       val tmpR = getTmpReg()
  592.       in
  593.       do_immed_arith(M.SLTU,tmpR,a,n); 
  594.       emitBRANCH(true,Reg0,tmpR,lab);
  595.       freeTmpReg tmpR
  596.       end
  597.     | rangeChk _ = error "MipsCM.rangeChk"
  598.  
  599.  
  600.   fun floatreg (Direct fpr) = (case reg_rep fpr 
  601.                     of Freg' _ => fpr 
  602.                  | _ => error "MipsCM.floatreg: expected floatreg")
  603.     | floatreg _ = error "MipsCM.floatreg: expected floatreg"
  604.   local 
  605.       val real_tag = System.Tags.desc_reald
  606.       val lowOff = E.low_order_offset
  607.  
  608.       fun store_float(n',dst,offset) = 
  609.        case (reg_rep n', dst)
  610.         of (Freg' n, Direct dst') =>
  611.         if n mod 2 <> 0 then
  612.             error "MipsCM.store_float: bad float reg"
  613.         else 
  614.             (do_immed_mem (M.SWC1,Freg(n+1-lowOff),dst',offset+4);
  615.              do_immed_mem (M.SWC1,Freg(n+lowOff),dst',offset))
  616.          | _ => error "MipsCM.store_float: bad args"
  617.  
  618.       fun load_float(dest',src,offset) =
  619.       case reg_rep dest'
  620.         of Freg' dest =>
  621.         if dest mod 2 <> 0 then error "MipsCM.load_float.1"
  622.         else (case src
  623.                of Direct src' => 
  624.                (do_immed_mem(M.LWC1,Freg(dest+lowOff),src',offset);
  625.                 do_immed_mem(M.LWC1,Freg(dest+1-lowOff),src',offset+4))
  626.                | ImmedLab lab => 
  627.                  let val tmpR = getTmpReg()
  628.                  in emitSDI(LOADF(Freg dest,lab,offset,tmpR));
  629.                  freeTmpReg tmpR
  630.                  end
  631.                | _ => error "MipsCM.load_float.3")
  632.          | _ => error "MipsCM.load_float.2"
  633.  
  634.   in
  635.       fun storefloat(src,Direct dst) =
  636.       (case reg_rep dst 
  637.         of Reg' result =>
  638.         (store_float(floatreg src,dataptr,4);
  639.          let val tmpR = getTmpReg()
  640.          in
  641.              emit (M.ADD(tmpR,Reg0,Immed16Op real_tag));
  642.              emit (M.SW(tmpR,dataptr',Immed16Off 0));
  643.              emit (M.ADD(Reg result,dataptr',Immed16Op 4));
  644.              emit (M.ADD(dataptr',dataptr',Immed16Op 12));
  645.             freeTmpReg tmpR
  646.         end)
  647.          | _ => error "MipsCM.storefloat: bad args")
  648.     | storefloat _ = error "MipsCM.storefloat: bad args.2"
  649.  
  650.       fun loadfloat(src, dst) = load_float(floatreg dst,src,0)
  651.                       (* y <- mem[x+4*(z-1)] *)
  652.       fun fetchindexd(Direct x, y, z) =
  653.       (case z 
  654.         of Immed i   => load_float(floatreg y, Direct x, 4*(i-1))
  655.          | Direct z' => let val tmpR = getTmpReg()
  656.                 in
  657.                 emit (M.SLL(tmpR,z',Int5 2));
  658.                 emit (M.ADD(tmpR,x,RegOp tmpR));
  659.                 load_float(floatreg y, Direct tmpR, ~4);
  660.                 freeTmpReg tmpR
  661.                 end
  662.          | _ => error "MipsCM.fetchindexd")
  663.     | fetchindexd _ = error "MipsCM.fetchindexd"
  664.  
  665.                       (* mem[y+4*(z-1)] <- x *)
  666.       fun storeindexd(x, Direct y, z) =
  667.       (case z 
  668.         of Immed i => store_float(floatreg x,Direct y, 4*(i-1))
  669.          | Direct z' => let val tmpR = getTmpReg()
  670.                 in
  671.                 emit (M.SLL(tmpR,z',Int5 2));
  672.                 emit (M.ADD(tmpR,y,RegOp tmpR));
  673.                 store_float(floatreg x,Direct tmpR,~4);
  674.                 freeTmpReg tmpR
  675.                 end
  676.          | _ => error "MipsCM.storeindexd")
  677.     | storeindexd _ = error "MipsCM.storeindexd"
  678.   end
  679.   local 
  680.       fun floating_arith f (x,y,z) = emit(f(floatreg x,floatreg y,floatreg z))
  681.  
  682.       fun compare(LSS,op1,op2) = (emit(M.SLT_DOUBLE(op1,op2)); true)
  683.     | compare(GEQ,op1,op2) = (emit(M.SLT_DOUBLE(op1,op2)); false)
  684.     | compare(EQL,op1,op2) = (emit(M.SEQ_DOUBLE(op1,op2)); true)
  685.     | compare(NEQ,op1,op2) = (emit(M.SEQ_DOUBLE(op1,op2)); false)
  686.     | compare(LEQ,op1,op2) = compare(GEQ,op2,op1)
  687.     | compare(GTR,op1,op2) = compare(LSS,op2,op1)
  688.   in
  689.       fun fmuld(x,y,z)       = floating_arith M.MUL_DOUBLE (z,x,y)
  690.       fun fdivd(x,y,z)       = floating_arith M.DIV_DOUBLE (z,x,y)
  691.       fun faddd(x,y,z)       = floating_arith M.ADD_DOUBLE (z,x,y)
  692.       fun fsubd(x,y,z)       = floating_arith M.SUB_DOUBLE (z,x,y)
  693.       fun fnegd(op1,result) = emit(M.NEG_DOUBLE(floatreg result,floatreg op1))
  694.       fun fabsd(op1,result) = emit(M.ABS_DOUBLE(floatreg result,floatreg op1))
  695.  
  696.       fun fbranchd (cond, op1, op2, ImmedLab label) = 
  697.       emitBRANCH_COP1(compare(cond,floatreg op1,floatreg op2),label)
  698.     | fbranchd _ = error "MipsCM.fbranchd: insane target"
  699.   end
  700.  
  701.   fun cvti2d(Direct src,dst as Direct dst') = 
  702.       (case (reg_rep src, reg_rep dst')
  703.         of (Reg' _, Freg' _) => (emit (M.MTC1(src, dst'));
  704.                    emit (M.CVTI2D(dst', dst'))))
  705.     | cvti2d(Immed n, dst) = 
  706.                    let val tmpR = getTmpReg()
  707.             in  do_immed_arith(M.ADD,tmpR,Reg0,n);
  708.             cvti2d(Direct tmpR,dst);
  709.             freeTmpReg tmpR
  710.            end
  711.  
  712.   val comment = C.comment
  713. end
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720.